package com.hcjy.common.handler;

import cn.dev33.satoken.exception.NotLoginException;
import com.hcjy.common.exception.CommonException;
import com.hcjy.entity.resp.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;

/**
 * @author Guqier
 * @version 1.0
 * @date 2024/1/23 下午 4:39
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(CommonException.class)
    public R doCustomerException(Exception e) {
        return R.fail(0, e.getMessage());
    }

    /**
     * 未登录异常
     * @param nle 异常对象
     * @return 响应
     */
    @ExceptionHandler(NotLoginException.class)
    public R doNotLoginException(NotLoginException nle) {
        if(nle.getType().equals(NotLoginException.NOT_TOKEN)) {
            return R.fail(R.Archetype.USER_NOT_LOGIN);
        }
        else if(nle.getType().equals(NotLoginException.INVALID_TOKEN)) {
            return R.fail(R.Archetype.INVALID_TOKEN);
        }
        else if(nle.getType().equals(NotLoginException.TOKEN_TIMEOUT) || nle.getType().equals(NotLoginException.BE_REPLACED)) {
            return R.fail(R.Archetype.TOKEN_EXPIRED);
        }
        else {
            return R.fail(R.Archetype.USER_NOT_LOGIN);
        }
    }

    /**
     * 约束异常
     * @param e 异常对象
     * @return 响应
     */
    @ExceptionHandler(DuplicateKeyException.class)
    public R doDuplicateKeyException(DuplicateKeyException e) {
        return R.fail(0, e.getMessage());
    }

    /**
     * Servlet参数校验异常
     * @param e 异常对象
     * @return 响应
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public R doMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        return R.fail(102, "类型为【" + e.getParameterType() + "】的必要参数【" + e.getParameterName() + "】不能为空");
    }

    /**
     * JSON请求校验结果，也就是请求中对实体标记了@RequestBody
     * @param e 异常对象
     * @return 响应结果
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public R handMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        // 拼接响应结果
        BindingResult bindingResult = e.getBindingResult();
        return extractException(bindingResult.getAllErrors());
    }

    /**
     * 表单请求校验结果处理
     * @param bindException 异常请求对象
     * @return 响应结果
     */
    @ExceptionHandler(value = BindException.class)
    public R errorHandler(BindException bindException) {
        BindingResult bindingResult = bindException.getBindingResult();
        return extractException(bindingResult.getAllErrors());
    }

    /**
     * 请求方式不支持异常
     * @param e 异常对象
     * @return 异常响应
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public R notSupportMethodException(HttpRequestMethodNotSupportedException e) {
        return R.fail(101, e.getMessage());
    }

    @ExceptionHandler(NoHandlerFoundException.class)
    public R noHandlerFoundException(NoHandlerFoundException e) {
        return R.fail(R.Archetype.NO_HANDLER_FOUND);
    }

    @ExceptionHandler(Exception.class)
    public R doException(Exception e) {
        log.error("系统异常：{}", getTraceToString(e));
        return R.fail(999, "系统异常");
    }

    /**
     * 数据校验异常响应结果封装方法
     * @param errorList 错误列表
     * @return 响应结果
     */
    private R extractException(List<ObjectError> errorList) {
        StringBuilder errorMsg = new StringBuilder();
        for (ObjectError objectError : errorList) {
            errorMsg.append(objectError.getDefaultMessage()).append(";");
        }
        // 移出最后的分隔符
        errorMsg.delete(errorMsg.length() - 1, errorMsg.length());
        return R.fail(101, errorMsg.toString());
    }

    /**
     * 获取异常跟踪栈信息
     * @param throwable 异常对象
     * @return 异常跟踪栈信息
     */
    public static String getTraceToString(Throwable throwable){
        StringWriter stringWriter=new StringWriter();
        PrintWriter writer=new PrintWriter(stringWriter);
        throwable.printStackTrace(writer);
        StringBuffer buffer=stringWriter.getBuffer();
        return buffer.toString();
    }


}
